/* (c) 2008,2009 Jonathan Hogg and Andreas Grothey, University of Edinburgh
 *
 * This file is part of SML.
 *
 * SML is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, using version 3 of the License.
 *
 * SML is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */

#include "Sml.h"
#include "AmplModel.h"
#include "backend.h"
#include "ExpandedModel.h"
#include "ExpandedModel2.h"
#include "ModelContext.h"
#include "GlobalVariables.h"
#include "global_util_functions.h"
#include <iostream>
#include <sys/stat.h>
#include <time.h>
#include <vector>
#include <string>

#ifdef HAVE_DIRECT_H
#include <direct.h> // for mkdir() under MinGW
#endif

using namespace std;

extern int parse_model();

Sml* Sml::_sml = NULL;

Sml* Sml::instance()
{
	if(!_sml)
	{
		_sml = new Sml();
	}
	return _sml;
}

void Sml::deleteInstance()
{
	if(_sml)
	{
		delete _sml;
		_sml = NULL;
	}
}

Sml::Sml()
{
	LOG("Sml processor created...scriptList["<<scriptNameList.size()<<"]");
}

Sml::~Sml()
{
	LOG("Sml destructor called...");
}

void Sml::print_copy_right(ostream &out)
{
	out << "Structure-conveying Modelling Language, version - trunk" << endl;
	out << "(c) 2012 Jonathan Hogg, Andreas Grothey, Feng Qiang, University of Edinburgh." << endl;
	out << "Released under LGPL v3" << endl;
	out << "CPU:: CLOCKS_PER_SEC ["<<CLOCKS_PER_SEC<<"]"<<endl;
}

int Sml::sml_gen_pre_checks()
{
	FILE *inputFile = fopen(GlobalVariables::modelfilename.c_str(),"r");
	if (!inputFile)
	{
		cerr << "ERROR: Cannot open file '" << GlobalVariables::modelfilename << "'.\n";
     	return 1;
   	}
	fclose(inputFile);

   	// check that we can access the datafile, otherwise we get an ugly message
   	// from amplsolver in case the file cannot be accessed
   	inputFile = fopen(GlobalVariables::datafilename.c_str(), "r");
   	if (!inputFile)
   	{
   		cerr << "Cannot open file: '" << GlobalVariables::datafilename << "'.\n";
     	return 2;
   	}
   	fclose(inputFile);

   	int errcode = createTmpDirIfNotPresent();
	if(errcode)
	{
		return errcode;
	}
   	// Change directory to make things work
   	errcode = chdir("tmp");
   	if (errcode)
   	{
   	   	cerr << "Could not change working directory to 'tmp/'\n";
   	   	cerr << "Cannot continue\n";
   		return 3;
   	}
   	// Restore original directory
   	errcode = chdir("..");
   	if (errcode)
   	{
   	   	cerr << "Could not change working directory to 'tmp/'\n";
   		cerr << "Cannot continue\n";
    	return 4;
   	}


   	return 0;
}

void Sml::process_model_file()
{
	int errcode = Sml::sml_gen_pre_checks();
	assert(errcode ==0);
	errcode = parse_model();
	assert(errcode ==0);
}

ExpandedModelAbstract* Sml::generate_em2()
{
	LOG("============== ExpandedModel2 Generation =============================");
	//build up root ModelContext
	//and process for each submodels
	LOG_SYS_MEM("BeforeNewModelContext");
	ModelContext* rootContext = new ModelContext(NULL);
	LOG_SYS_MEM("AfterNewModelContext");
	ExpandedModelAbstract* emRoot = AmplModel::root->createExpandedModel2(rootContext,NULL);
	LOG("============== END ExpandedModel2 Generation =============================");

	return emRoot;
}


ExpandedModelAbstract* Sml::generate_em()
{
	/** @todo At the moment we are using AMPL to process the data file (see
	*  process_model() in backend.cpp or expandSet() expandStagesOfComp()
	*  in StochModel.cpp). Eventually, we will do it ourselves.
	*/


    // change working directory back to tmp/ for processing model
	int	errcode = chdir("tmp");
	assert(errcode == 0);

	TIMER_START("SML_ADD_DUMP_OBJ");
	AmplModel::root->addDummyObjective();
	TIMER_STOP("SML_ADD_DUMP_OBJ");
	AmplModel::root->dump("logModel.dat");

	/* Write out and ampl model and scripts*/
	TIMER_START("AMPL_MODEL_SCRIPT_GENERATION");
	errcode = process_model(AmplModel::root, GlobalVariables::datafilename);
	TIMER_STOP("AMPL_MODEL_SCRIPT_GENERATION");
	if (errcode)
	{
		return NULL;
	}

	// process ampl scripts
	TIMER_START("AMPL_SCRIPT_PROCESS");
	processAmplScripts();
	TIMER_STOP("AMPL_SCRIPT_PROCESS");


	TIMER_START("SML_EM_GENERATION");
	LOG("------------- Generate ExpandedModel tree ------------ ");
	ExpandedModel *em = AmplModel::root->createExpandedModel("root", "");
	if (GlobalVariables::debug){
		em->print();
	}
	TIMER_STOP("SML_EM_GENERATION");

	return em;
}

